<?php
###########################################################################
#  Copyright (C) 2006-2007 Glyphix, Inc. <briz@glyphix.com>               #
#                                                                         #
#  Permission is hereby granted, free of charge, to any person obtaining  #
#  a copy of this software and associated documentation files (the        #
#  "Software"), to deal in the Software without restriction, including    #
#  without limitation the rights to use, copy, modify, merge, publish,    #
#  distribute, sublicense, and/or sell copies of the Software, and to     #
#  permit persons to whom the Software is furnished to do so, subject to  #
#  the following conditions:                                              #
#                                                                         #
#  The above copyright notice and this permission notice shall be         #
#  included in all copies or substantial portions of the Software.        #
#                                                                         #
#  Except as contained in this notice, the name(s) of the above           #
#  copyright holders shall not be used in advertising or otherwise to     #
#  promote the sale, use or other dealings in this Software without       #
#  prior written authorization.                                           #
#                                                                         #
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        #
#  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     #
#  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. #
#  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR      #
#  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,  #
#  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR  #
#  OTHER DEALINGS IN THE SOFTWARE.                                        #
###########################################################################

/**
 * GXXSL
 *
 * The XSL transformation class for GXPage.
 * It processes the provided xml (object or string) with the provided xsl (object or string), and returns the results in the requested format.
 * @author		Brad Brizendine <briz@glyphix.com>
 * @link		http://www.glyphix.com/
 * @license		http://opensource.org/licenses/bsd-license.php BSD License
 * @version		1.0
 * @package		GXPage
 * @subpackage	Engine
 * @copyright	Copyright 2006 - 2007, Glyphix, Inc.
 * @uses		SingletonPattern
 */

class GXXSL extends SingletonPattern {

	const TO_DOC = 'TRANSFORM_TO_DOC';
	const TO_XML = 'TRANSFORM_TO_XML';
	const TO_GXDOM = 'TRANSFORM_TO_GXDOM';

	private $encoding = 'UTF-8';

	/**
	 * getInstance
	 *
     * Returns the single unique instance of this class.
	 * @return object unique instance of this object
     */
	public static function getInstance(){
		return SingletonPattern::getSingleton( __CLASS__ );
	}

	/**
	 * __construct
	 * @return boolean
	 */
	function __construct(){
		return true;
	}

	/**
	 * setEncoding
	 *
	 * Sets the transformation character encoding.
	 * @param string $encoding the encoding string (must be a valid character encoding value)
	 * @return boolean
	 */
	public function setEncoding( $str = 'UTF-8' ){
		$this->encoding = $str;
		return true;
	}

	/**
	 * process
	 *
	 * Creates an XSLT processor, applies any supplied parameters and then processes the provided XML with the provided XSL.
	 * XML and XSL can be either objects (of GXDOM, DOMDocument or SimpleXML) or strings.
	 * It will return the requested data type (xml string, DOMDocument or GXDOM).
	 * @param mixed $xml the xml to be processed, as an object or a string
	 * @param mixed $sheet the stylesheet to use as the processor, as an object or a string
	 * @param constant $to the GXXSL constant specifying the format of the returned result
	 * @return mixed whatever is specified as the return value or false on failure
	 */
	function process( $xml = null, $sheet = null, $params = null, $to = GXXSL::TO_XML ) {
		if( !$xml ){
			trigger_error( 'No XML data received', E_USER_ERROR );
			return false;
		}
		if( !$sheet ){
			trigger_error( 'No stylesheet', E_USER_ERROR );
			return false;
		}

		// handle last 2 parameters
		if( !is_array($params) && ($params === GXXSL::TO_DOC || $params === GXXSL::TO_XML || $params === GXXSL::TO_GXDOM) ){
			$to = $params;
			$params = null;
		}

		// make sure xml is a document
		$xml = $this->getDoc($xml);
		$sheet = $this->getDoc($sheet);
		// sanity check
		if( !$xml || !$sheet ){
			trigger_error( 'Unable to perform transformation because unable to load either xml, xsl or both', E_USER_ERROR );
			return false;
		}

		// add parameters to the processor
		$proc = new XSLTProcessor();
		if(is_array($params)){
			foreach ($params as $key => $value){
				$proc->setParameter('', $key, $value);
			}
		}

		// set the encoding
		$proc->setParameter('','encoding',$this->encoding);

		// import the stylesheet
		if( !@$proc->importStyleSheet($sheet) ){
			trigger_error( 'Unable to import stylesheet', E_USER_ERROR );
			return false;
		}

		// determine what to return
		switch( $to ){
			case GXXSL::TO_DOC:
			case GXXSL::TO_GXDOM:
				$f = 'transformToDoc';
				break;
			case GXXSL::TO_XML:
			default:
				$f = 'transformToXML';
		}

		// now process
		if( !($result = @$proc->$f($xml)) ){
			trigger_error( 'Unable to perform XSL transformation: ' .print_r($result,true) .'; check your web server error log for more detailed information', E_USER_ERROR );
			return false;
		}

		// if we're supposed to return GXDOM
		if( $to === GXXSL::TO_GXDOM ){
			// wrap it in gxdom
			$tmp = null;
			$doc = new GXDOM(null,$result,null,null,$tmp,null,true);
			return $doc;
		}
		// otherwise, just return the raw results
		return $result;
	}

	/**
	 * getDoc
	 *
	 * Returns a DOMDocument from the provided parameter.
	 * @param mixed $in the item to work with (xml string, DOMDocument, SimpleXML object, or GXDOM object)
	 * @return object DOMDocument
	 */
	public function getDoc( $in = null ){
		switch(true){
			case is_string($in) && strlen($in)<1024 && is_file($in):
				try{
					// using DOMDocument::load throws an E_STRICT warning
					$doc = new DOMDocument();
					$doc->load($in);
				}catch( DOMException $e ){
					trigger_error( 'Unable to load XML file ' .$in .': not well-formed (' .print_r($in,true) .')', E_USER_ERROR );
					return false;
				}
				return $doc;
				break;
			case is_string($in):
				try{
					// using DOMDocument::load throws an E_STRICT warning
					$doc = new DOMDocument();
					$doc->loadXML($in);
				}catch( DOMException $e ){
					trigger_error( 'Unable to load XML string (not well-formed) ' .$in .'::' .print_r($e,true), E_USER_ERROR );
					return false;
				}
				return $doc;
				break;
			case get_class($in) == 'DOMDocument':
				return $in;
			case get_class($in) == 'GXDOM':
				return $in->doc;
				break;
			case get_class($in) == 'SimpleXML' || get_class($in) == 'SimpleXMLElement':
				return dom_import_simplexml($in);
				break;
			default:
				trigger_error( 'Cannot determine doc type', E_USER_ERROR );
				return false;
		}
	}

}

?>
